﻿using System;
using System.Diagnostics;
using System.IO;

namespace PhiStore.Experiments.Encryption
{
    class EncryptionExperiment: IExperiment
    {
        object critical = new object();
        Boolean completed = false;

        byte[] data;
        MemoryStream dataStream;


        public EncryptionExperiment()
        {
            Random rand = new Random();
            data = new byte[1024*1024];
            rand.NextBytes(data);
            dataStream = new MemoryStream();
            
            for (int i = 0; i < 10; i++) //10 times the data for symmetric encryption
            {
                dataStream.Write(data, 0, data.Length);
            }
        }

        public bool IsComplete()
        {
            lock (critical)
            {
                return completed;
            }
        }

        public string getResults()
        {
            if (!IsComplete())
            {
                return "";
            }
            else
            {
                double MB = ((double)dataStream.Length) / 1024 / 1024;
                double KB = ((double)data.Length) / 1024;

                string result = "RSA Encrypt: " + (KB / (RSApublicEncryptionTime / 1000)).ToString("0.##") + " KB/s\r\n";
                result += "RSA Decrypt: " + (KB / (RSAprivateDecryptionTime / 1000)).ToString("0.##") + " KB/s\r\n";
                result += "AES Encrypt: " + (MB / (AESEncryptTime / 1000)).ToString("0.##") + " MB/s\r\n";
                result += "AES Decrypt: " + (MB / (AESDecryptTime / 1000)).ToString("0.##") + " MB/s\r\n";
                
                result += "DES Encrypt: " + (MB / (DESEncryptTime / 1000)).ToString("0.##") + " MB/s\r\n";
                result += "DES Decrypt: " + (MB / (DESDecryptTime / 1000)).ToString("0.##") + " MB/s\r\n";
                result += "Triple DES Encrypt: " + (MB / (TripleDESEncryptTime / 1000)).ToString("0.##") + " MB/s\r\n";
                result += "Triple DES Decrypt: " + (MB / (TripleDESDecryptTime / 1000)).ToString("0.##") + " MB/s\r\n";

                return result;
            }
        }

        double RSApublicEncryptionTime = 0;
        double RSAprivateDecryptionTime = 0;
        double DESEncryptTime = 0;
        double DESDecryptTime = 0;
        double TripleDESEncryptTime = 0;
        double TripleDESDecryptTime = 0;
        double AESEncryptTime = 0;
        double AESDecryptTime = 0;

        public void Run()
        {
            Stopwatch watch = new Stopwatch();

            #region RSA
            RSA rsa = new RSA();

            watch.Start();
            byte[] publicEncrypted = rsa.EncryptPublic(data);
            watch.Stop();
            RSApublicEncryptionTime = watch.ElapsedMilliseconds;

            watch.Restart();
            byte[] privateDecrypted = rsa.DecryptPrivate(publicEncrypted);
            watch.Stop();
            RSAprivateDecryptionTime = watch.ElapsedMilliseconds;

            publicEncrypted = null;
            privateDecrypted = null;
           
            rsa = null;
            System.GC.Collect();
            #endregion

            #region DES
            DES des = new DES("hello");

            watch.Restart();
            Stream desEncrypted = des.Encrypt(dataStream);
            watch.Stop();

            DESEncryptTime = watch.ElapsedMilliseconds;

            watch.Restart();
            Stream desDecrypted = des.Decrypt(desEncrypted);
            watch.Stop();

            DESDecryptTime = watch.ElapsedMilliseconds;

            dataStream.Position = 0;
            desDecrypted = null;
            desEncrypted = null;
            des = null;
            System.GC.Collect();
            #endregion

            #region Triple DES
            TripleDES tripledes = new TripleDES("hello");

            watch.Restart();
            Stream tripledesEncrypted = tripledes.Encrypt(dataStream);
            watch.Stop();

            TripleDESEncryptTime = watch.ElapsedMilliseconds;

            watch.Restart();
            Stream tripledesDecrypted = tripledes.Decrypt(tripledesEncrypted);
            watch.Stop();

            TripleDESDecryptTime = watch.ElapsedMilliseconds;

            dataStream.Position = 0;
            tripledesEncrypted = null;
            tripledesDecrypted = null;
            tripledes = null;
            System.GC.Collect();
            #endregion

            #region AES
            AES aes = new AES("hello");

            watch.Restart();
            Stream aesEncrypted = aes.Encrypt(dataStream);
            watch.Stop();

            AESEncryptTime = watch.ElapsedMilliseconds;

            watch.Restart();
            Stream aesDecrypted = aes.Decrypt(aesEncrypted);
            watch.Stop();

            AESDecryptTime = watch.ElapsedMilliseconds;

            dataStream.Position = 0;
            aesEncrypted = null;
            aesDecrypted = null;
            aes = null;
            System.GC.Collect();


            #endregion

            lock (critical)
            {
                completed = true;
            }
        }
    }
}
